#include <gtest/gtest.h>
#include "base_shared_ring_buffer.h"
#include "base_log.h"
#include <chrono>
#include <thread>
#include <vector>
#include <random>
#include <algorithm>
#include <string>
#include <sys/wait.h>
#include <unistd.h>

using namespace El::Base;

class SharedRingBufferTest : public ::testing::Test {
protected:
    void SetUp() override
    {
        // 确保没有残余的共享内存
        CleanupSharedMemory();
    }

    void TearDown() override
    {
        // 清理测试使用的共享内存
        CleanupSharedMemory();
    }

    void CleanupSharedMemory()
    {
        // 清理测试用的共享内存
        system("rm -f /dev/shm/test_rb_*");
    }

    // 生成随机数据
    std::vector<uint8_t> GenerateRandomData(size_t size)
    {
        std::vector<uint8_t> data(size);
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_int_distribution<> distrib(0, 255);

        for (size_t i = 0; i < size; ++i) {
            data[i] = static_cast<uint8_t>(distrib(gen));
        }

        return data;
    }
};

// 测试尝试用错误的大小打开已存在的环形缓冲区
TEST_F(SharedRingBufferTest, OpenWithWrongSize)
{
    const std::string testName = "/test_rb_wrong_size";
    const size_t bufferSize = 1024;

    // 创建写入者
    auto writer = SharedRingBuffer::Create(testName, bufferSize, true);
    ASSERT_NE(writer, nullptr);

    // 尝试用错误的大小创建读取者
    auto reader = SharedRingBuffer::Create(testName, bufferSize * 2, false);
    EXPECT_EQ(reader, nullptr);

    // 清理
    writer->Close();
}

// 测试基本的读写操作
TEST_F(SharedRingBufferTest, BasicReadWrite)
{
    const std::string testName = "/test_rb_basic_rw";
    const size_t bufferSize = 1024;

    // 创建写入者和读取者
    auto writer = SharedRingBuffer::Create(testName, bufferSize, true);
    auto reader = SharedRingBuffer::Create(testName, bufferSize, false);
    ASSERT_NE(writer, nullptr);
    ASSERT_NE(reader, nullptr);

    // 测试数据
    const std::string testData = "Hello, Shared Ring Buffer!";
    const size_t dataSize = testData.size();

    // 写入数据
    ssize_t written = writer->Write(testData.c_str(), dataSize);
    EXPECT_EQ(written, dataSize);

    // 读取数据
    char readBuffer[256] = {0};
    ssize_t bytesRead = reader->Read(readBuffer, sizeof(readBuffer));
    EXPECT_EQ(bytesRead, dataSize);
    EXPECT_STREQ(readBuffer, testData.c_str());

    // 清理
    writer->Close();
    reader->Close();
}

// 测试写满环形缓冲区然后读取
TEST_F(SharedRingBufferTest, WriteFillAndRead)
{
    const std::string testName = "/test_rb_fill";
    const size_t bufferSize = 1024;

    auto writer = SharedRingBuffer::Create(testName, bufferSize, true);
    auto reader = SharedRingBuffer::Create(testName, bufferSize, false);
    ASSERT_NE(writer, nullptr);
    ASSERT_NE(reader, nullptr);

    // 生成随机数据
    auto testData = GenerateRandomData(bufferSize - 100); // 留出一点空间给头部信息

    // 写入数据
    ssize_t written = writer->Write(testData.data(), testData.size());
    EXPECT_EQ(written, testData.size());

    // 读取数据
    std::vector<uint8_t> readBuffer(testData.size());
    ssize_t bytesRead = reader->Read(readBuffer.data(), readBuffer.size());
    EXPECT_EQ(bytesRead, testData.size());

    // 验证数据一致性
    for (size_t i = 0; i < testData.size(); ++i) {
        EXPECT_EQ(readBuffer[i], testData[i]) << "数据不一致在位置 " << i;
    }

    // 清理
    writer->Close();
    reader->Close();
}

// 测试环形缓冲区的环绕写入和读取
TEST_F(SharedRingBufferTest, WrapAroundWriteRead)
{
    const std::string testName = "/test_rb_wrap";
    const size_t bufferSize = 1024;

    auto writer = SharedRingBuffer::Create(testName, bufferSize, true);
    auto reader = SharedRingBuffer::Create(testName, bufferSize, false);
    ASSERT_NE(writer, nullptr);
    ASSERT_NE(reader, nullptr);

    // 步骤：
    // 1. 写入数据块，大约为缓冲区大小的一半
    // 2. 读取这些数据
    // 3. 再次写入另一块数据，使缓冲区几乎被占满
    // 4. 读取这些数据
    // 5. 写入第三块数据，这将导致环绕
    // 6. 读取并验证数据

    // 使用稍小一点的块大小，防止环形缓冲区头部占用空间影响测试
    const size_t chunkSize = (bufferSize / 2) - 64;

    // 第一次写入
    auto data1 = GenerateRandomData(chunkSize);
    ssize_t written1 = writer->Write(data1.data(), data1.size());
    EXPECT_EQ(written1, static_cast<ssize_t>(data1.size()));

    // 读取第一块数据
    std::vector<uint8_t> readBuffer1(chunkSize);
    ssize_t bytesRead1 = reader->Read(readBuffer1.data(), readBuffer1.size());
    EXPECT_EQ(bytesRead1, static_cast<ssize_t>(chunkSize));

    // 验证第一块数据
    for (size_t i = 0; i < chunkSize; ++i) {
        EXPECT_EQ(readBuffer1[i], data1[i]) << "第一块数据不一致在位置 " << i;
    }

    // 第二次写入
    auto data2 = GenerateRandomData(chunkSize);
    ssize_t written2 = writer->Write(data2.data(), data2.size());
    EXPECT_EQ(written2, static_cast<ssize_t>(data2.size()));

    // 第三次写入，这可能会导致环绕或部分写入
    auto data3 = GenerateRandomData(chunkSize);
    ssize_t written3 = writer->Write(data3.data(), data3.size());

    // 我们不确定能写入多少字节，但应该能写入一些数据
    EXPECT_GT(written3, 0);

    // 读取第二块数据
    std::vector<uint8_t> readBuffer2(chunkSize);
    ssize_t bytesRead2 = reader->Read(readBuffer2.data(), readBuffer2.size());
    EXPECT_EQ(bytesRead2, static_cast<ssize_t>(chunkSize));

    // 验证第二块数据
    for (size_t i = 0; i < chunkSize; ++i) {
        EXPECT_EQ(readBuffer2[i], data2[i]) << "第二块数据不一致在位置 " << i;
    }

    // 读取第三块数据（可能只能读取部分）
    std::vector<uint8_t> readBuffer3(written3);
    ssize_t bytesRead3 = reader->Read(readBuffer3.data(), readBuffer3.size());
    EXPECT_EQ(bytesRead3, written3);

    // 验证第三块数据（仅验证实际写入的部分）
    for (size_t i = 0; i < static_cast<size_t>(written3); ++i) {
        EXPECT_EQ(readBuffer3[i], data3[i]) << "第三块数据不一致在位置 " << i;
    }

    // 清理
    writer->Close();
    reader->Close();
}

// 测试多个读者
TEST_F(SharedRingBufferTest, MultipleReaders)
{
    const std::string testName = "/test_rb_multi_readers";
    const size_t bufferSize = 1024;

    auto writer = SharedRingBuffer::Create(testName, bufferSize, true);
    ASSERT_NE(writer, nullptr);

    // 创建多个读者
    const int numReaders = 5;
    std::vector<std::shared_ptr<SharedRingBuffer>> readers;

    for (int i = 0; i < numReaders; ++i) {
        auto reader = SharedRingBuffer::Create(testName, bufferSize, false);
        ASSERT_NE(reader, nullptr);
        readers.push_back(reader);
    }

    // 测试数据
    const std::string testData = "Message for all readers";
    const size_t dataSize = testData.size();

    // 写入数据
    ssize_t written = writer->Write(testData.c_str(), dataSize);
    EXPECT_EQ(written, dataSize);

    // 所有读者读取数据
    for (int i = 0; i < numReaders; ++i) {
        char readBuffer[256] = {0};
        ssize_t bytesRead = readers[i]->Read(readBuffer, sizeof(readBuffer));
        EXPECT_EQ(bytesRead, dataSize);
        EXPECT_STREQ(readBuffer, testData.c_str()) << "Reader " << i << " got incorrect data";
    }

    // 清理
    writer->Close();
    for (auto &reader : readers) {
        reader->Close();
    }
}

// 测试等待数据
TEST_F(SharedRingBufferTest, WaitForData)
{
    const std::string testName = "test_rb_wait"; // 移除前导斜杠
    const size_t bufferSize = 1024;

    auto writer = SharedRingBuffer::Create(testName, bufferSize, true);
    auto reader = SharedRingBuffer::Create(testName, bufferSize, false);
    ASSERT_NE(writer, nullptr);
    ASSERT_NE(reader, nullptr);

    // 测试数据
    const std::string testData = "Waited data";
    const size_t dataSize = testData.size();

    // 启动线程来延迟写入数据
    std::thread writerThread([&]() {
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        ssize_t written = writer->Write(testData.c_str(), dataSize);
        EXPECT_EQ(written, static_cast<ssize_t>(dataSize));
    });

    // 等待数据（超时1秒）
    bool dataAvailable = reader->WaitForData(1000);
    EXPECT_TRUE(dataAvailable);

    // 读取数据
    if (dataAvailable) {
        char readBuffer[256] = {0};
        ssize_t bytesRead = reader->Read(readBuffer, sizeof(readBuffer));
        EXPECT_EQ(bytesRead, static_cast<ssize_t>(testData.size()));
        EXPECT_EQ(std::string(readBuffer), testData);
    }

    // 确保写入线程结束
    if (writerThread.joinable()) {
        writerThread.join();
    }

    // 清理资源
    writer->Close();
    reader->Close();
}

// 测试清空缓冲区
TEST_F(SharedRingBufferTest, ClearBuffer)
{
    const std::string testName = "test_rb_clear"; // 移除前导斜杠
    const size_t bufferSize = 1024;

    auto writer = SharedRingBuffer::Create(testName, bufferSize, true);
    auto reader = SharedRingBuffer::Create(testName, bufferSize, false);
    ASSERT_NE(writer, nullptr);
    ASSERT_NE(reader, nullptr);

    // 写入一些数据
    const std::string testData = "Data to be cleared";
    const size_t dataSize = testData.size();

    ssize_t written = writer->Write(testData.c_str(), dataSize);
    EXPECT_EQ(written, dataSize);

    // 验证可读大小
    size_t readableSize = reader->GetReadableSize();
    EXPECT_EQ(readableSize, dataSize);

    // 清空缓冲区
    writer->Clear();

    // 清空后，可读大小应该为0
    readableSize = reader->GetReadableSize();
    EXPECT_EQ(readableSize, 0);

    // 清理
    writer->Close();
    reader->Close();
}

// 进程间通信测试
TEST_F(SharedRingBufferTest, InterProcessCommunication)
{
    const std::string testName = "test_rb_ipc";
    const size_t bufferSize = 1024;
    const std::string testData = "IPC test message";

    // 确保共享内存区域存在并可访问，先清理
    system("rm -f /dev/shm/test_rb_ipc");

    // 首先创建共享内存
    auto writer = SharedRingBuffer::Create(testName, bufferSize, true);
    ASSERT_TRUE(writer) << "Failed to create writer";
    LOG_INFO("Parent process: Created writer successfully");

    // 确保共享内存已经创建成功
    ASSERT_TRUE(access("/dev/shm/test_rb_ipc", F_OK) != -1) << "Shared memory file was not created";
    LOG_INFO("Parent process: Shared memory file exists at /dev/shm/test_rb_ipc");

    pid_t pid = fork();
    ASSERT_NE(pid, -1) << "Fork failed";

    if (pid == 0) {
        // 子进程：读取者
        LOG_INFO("Child process: Starting reader initialization");
        
        // 在子进程中，将writer标记为非写入者，防止删除共享内存
        if (writer) {
            LOG_INFO("Child process: Setting writer to non-writer mode");
            writer->SetWriterMode(false);
            LOG_INFO("Child process: About to reset writer pointer");
            writer.reset();
            LOG_INFO("Child process: Reset writer pointer completed");
        }

        // 检查共享内存文件是否存在 (1)
        if (access("/dev/shm/test_rb_ipc", F_OK) != -1) {
            LOG_INFO("Child process [Check 1]: Shared memory file exists");
        } else {
            LOG_ERROR("Child process [Check 1]: Shared memory file does not exist, errno: {} ({})", 
                     errno, strerror(errno));
            exit(EXIT_FAILURE);
        }

        // 给父进程一点时间确保共享内存已完全初始化
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        
        // 检查共享内存文件是否存在 (2)
        if (access("/dev/shm/test_rb_ipc", F_OK) != -1) {
            LOG_INFO("Child process [Check 2]: Shared memory file exists before opening");
        } else {
            LOG_ERROR("Child process [Check 2]: Shared memory file does not exist before opening, errno: {} ({})", 
                     errno, strerror(errno));
            exit(EXIT_FAILURE);
        }

        // 使用相同名称打开共享内存
        LOG_INFO("Child process: Attempting to create reader with name {} and size {}", testName, bufferSize);
        auto reader = SharedRingBuffer::Create(testName, bufferSize, false);
        if (!reader) {
            LOG_ERROR("Child process: Failed to create reader");
            exit(EXIT_FAILURE);
        }

        // 等待数据
        if (!reader->WaitForData(5000)) { // 增加等待时间到5秒
            LOG_ERROR("Timeout waiting for data in child process");
            exit(EXIT_FAILURE);
        }

        // 读取数据
        char buffer[256] = {0};
        ssize_t bytesRead = reader->Read(buffer, sizeof(buffer));

        // 验证数据并退出
        if (bytesRead != static_cast<ssize_t>(testData.size()) || std::string(buffer) != testData) {
            LOG_ERROR("Data verification failed in child process. Expected: {}, Got: {}", testData, buffer);
            exit(EXIT_FAILURE);
        }

        reader->Close();
        exit(EXIT_SUCCESS);
    } else {
        // 父进程：写入者
        // 等待一会儿，确保子进程已启动
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));

        // 写入数据
        ssize_t written = writer->Write(testData.c_str(), testData.size());
        EXPECT_EQ(written, static_cast<ssize_t>(testData.size()));

        // 等待子进程结束
        int status;
        ASSERT_NE(waitpid(pid, &status, 0), -1) << "Error waiting for child process";
        EXPECT_TRUE(WIFEXITED(status)) << "Child process did not exit normally";
        EXPECT_EQ(WEXITSTATUS(status), EXIT_SUCCESS) << "Child process exited with error";

        // 清理
        writer->Close();
    }
}

// 测试读者注册/注销
TEST_F(SharedRingBufferTest, ReaderRegistration)
{
    const std::string testName = "test_rb_registration"; // 移除前导斜杠
    const size_t bufferSize = 1024;

    auto writer = SharedRingBuffer::Create(testName, bufferSize, true);
    ASSERT_NE(writer, nullptr);

    // 创建和关闭多个读者，测试读者ID分配机制
    for (int i = 0; i < 10; ++i) {
        auto reader = SharedRingBuffer::Create(testName, bufferSize, false);
        ASSERT_NE(reader, nullptr);
        reader->Close(); // 立即关闭，释放读者ID
    }

    // 同时打开多个读者，但不超过最大限制
    std::vector<std::shared_ptr<SharedRingBuffer>> readers;
    for (int i = 0; i < 5; ++i) { // 使用较小的数量，减少测试时间
        auto reader = SharedRingBuffer::Create(testName, bufferSize, false);
        ASSERT_NE(reader, nullptr) << "无法创建读者 #" << i;
        readers.push_back(reader);
    }

    // 写入一些数据
    const std::string testData = "Message for all registered readers";
    ssize_t written = writer->Write(testData.c_str(), testData.size());
    EXPECT_EQ(written, static_cast<ssize_t>(testData.size()));

    // 验证所有读者都能读取到数据
    for (size_t i = 0; i < readers.size(); ++i) {
        char buffer[256] = {0};
        ssize_t bytesRead = readers[i]->Read(buffer, sizeof(buffer));
        EXPECT_EQ(bytesRead, static_cast<ssize_t>(testData.size())) << "读者 " << i << " 读取失败";
        EXPECT_STREQ(buffer, testData.c_str()) << "读者 " << i << " 数据不匹配";
    }

    // 清理
    writer->Close();
    for (auto &reader : readers) {
        reader->Close();
    }
}

// 测试大数据块的读写
TEST_F(SharedRingBufferTest, LargeDataTransfer)
{
    const std::string testName = "/test_rb_large_data";
    const size_t bufferSize = 128 * 1024; // 128KB

    auto writer = SharedRingBuffer::Create(testName, bufferSize, true);
    auto reader = SharedRingBuffer::Create(testName, bufferSize, false);
    ASSERT_NE(writer, nullptr);
    ASSERT_NE(reader, nullptr);

    // 生成大量数据（缓冲区大小的一半，避免填满）
    const size_t dataSize = bufferSize / 2;
    auto testData = GenerateRandomData(dataSize);

    // 写入数据
    ssize_t written = writer->Write(testData.data(), testData.size());
    EXPECT_EQ(written, static_cast<ssize_t>(dataSize));

    // 读取数据
    std::vector<uint8_t> readBuffer(dataSize);
    ssize_t bytesRead = reader->Read(readBuffer.data(), readBuffer.size());
    EXPECT_EQ(bytesRead, static_cast<ssize_t>(dataSize));

    // 验证数据（为了性能，只验证部分数据点）
    const size_t checkPoints = 100;
    const size_t stride = dataSize / checkPoints;

    bool dataMatches = true;
    for (size_t i = 0; i < checkPoints; ++i) {
        size_t idx = i * stride;
        if (readBuffer[idx] != testData[idx]) {
            dataMatches = false;
            ADD_FAILURE() << "数据不一致在位置 " << idx << "，预期: " << static_cast<int>(testData[idx])
                          << "，实际: " << static_cast<int>(readBuffer[idx]);
            // 只报告几个错误，避免输出过多
            if (i > 5)
                break;
        }
    }
    EXPECT_TRUE(dataMatches) << "数据验证失败";

    // 清理
    writer->Close();
    reader->Close();
}

// 测试心跳功能
TEST_F(SharedRingBufferTest, WriterHeartbeat)
{
    const std::string testName = "/test_rb_heartbeat";
    const size_t bufferSize = 1024;

    auto writer = SharedRingBuffer::Create(testName, bufferSize, true);
    auto reader = SharedRingBuffer::Create(testName, bufferSize, false);
    ASSERT_NE(writer, nullptr);
    ASSERT_NE(reader, nullptr);

    // 初始状态下，写入者应该是活跃的（已在Init时设置初始心跳时间戳）
    EXPECT_TRUE(reader->IsWriterActive());

    // 更新心跳
    writer->UpdateHeartbeat();
    EXPECT_TRUE(reader->IsWriterActive());

    // 使时间戳变旧来测试超时
    // 注：这里我们修改测试逻辑，因为我们不能轻易控制time()函数返回的时间
    // 改为通过sleep来让时间流逝，确保足够的时间来测试短超时
    std::this_thread::sleep_for(std::chrono::seconds(2));

    // 用非常短的超时检查心跳（应该超时）
    EXPECT_FALSE(reader->IsWriterActive(1)); // 1秒超时

    // 清理
    writer->Close();
    reader->Close();
}

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
